package zhongbo.javaweb.instagram.util;

import lombok.extern.slf4j.Slf4j;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 说明：
 * 线程安全的日期格式化工具类
 * <p>
 * 解决【sdf.format()】可能导致线程安全问题
 *
 * @author zhongboWork
 * @version 1.0
 * @since 2021-12-16 11:41
 * @see <a href="https://blog.csdn.net/u012516166/article/details/76764630">SimpleDateFormat 的线程安全问题</a>
 */
@Slf4j
public class DateFormatUtil {

    private static final String PATTERN = "yyyy-MM-dd HH:mm:ss.SSS";

    /**
     * 存放不同的日期模板格式的sdf的Map
     */
    private static ThreadLocal<Map<String, SimpleDateFormat>> sdfMap = ThreadLocal.withInitial(() -> {
        log.debug(Thread.currentThread().getName() + " init pattern: " + Thread.currentThread());
        return new HashMap<>();
    });

    /**
     * 返回一个SimpleDateFormat,每个线程只会new一次pattern对应的sdf
     *
     * @param pattern 时间格式
     * @return 格式化对象sdf
     */
    private static SimpleDateFormat getSdf(final String pattern) {
        Map<String, SimpleDateFormat> tl = sdfMap.get();
        SimpleDateFormat sdf = tl.get(pattern);
        if (sdf == null) {
            log.debug(Thread.currentThread().getName() + " put new sdf of pattern " + pattern + " to map");
            sdf = new SimpleDateFormat(pattern);
            tl.put(pattern, sdf);
        }
        return sdf;
    }

    /**
     * 这样每个线程只会有一个SimpleDateFormat
     *
     * @param date    时间对象
     * @param pattern 时间格式
     * @return 格式化后时间文本
     */
    public static String format(Date date, String pattern) {
        return getSdf(pattern).format(date);
    }

    /**
     * 这样每个线程只会有一个SimpleDateFormat
     *
     * @param date 时间对象
     * @return 格式化后时间文本
     */
    public static String format(Date date) {
        return getSdf(PATTERN).format(date);
    }

    /**
     * 这样每个线程只会有一个SimpleDateFormat
     *
     * @param dateMs  时间ms
     * @param pattern 时间格式
     * @return 格式化后时间文本
     */
    public static String format(long dateMs, String pattern) {
        return getSdf(pattern).format(dateMs);
    }

    /**
     * 这样每个线程只会有一个SimpleDateFormat
     *
     * @param dateMs 时间ms
     * @return 格式化后时间文本
     */
    public static String format(long dateMs) {
        return getSdf(PATTERN).format(dateMs);
    }

    /**
     * 解析时间文本到对象
     *
     * @param dateStr 时间文本
     * @param pattern 时间格式
     * @return 解析后段时间对象
     * @throws ParseException 解析异常
     */
    public static Date parse(String dateStr, String pattern)
            throws ParseException {
        return getSdf(pattern).parse(dateStr);
    }

    /**
     * 格式化时间 00:00:00:000 或 1D00:00:00:000
     *
     * @param timeMs 时间ms
     * @return 00:00:00:000 或 1D00:00:00:000
     */
    public static String formatMs(Long timeMs) {
        if (timeMs == null) {
            log.error("错误的参数调用 formatMs(), null");
            return "[error null timeMs]";
        }
        if (timeMs < 0) {
            log.error("错误的参数调用 formatMs(), timeMs: {}", timeMs);
            return String.format("[error timeMs < 0 (%s)]", timeMs);
        }
        long aDayMs = 86400000;
        String dayStr = "";
        if (timeMs >= aDayMs) {
            long day = timeMs / aDayMs;
            dayStr = day + "D";
        }
        long forDateTime = timeMs % aDayMs - 28800000;
        /*
         * 2021-12-16 10:49:39:999
         */
        String sdfPattern = "yyyy-MM-dd' 'HH:mm:ss:SSS";
        // 00:00:00:000 或 1D00:00:00:000
        return dayStr + DateFormatUtil.format(forDateTime, sdfPattern).substring(11);
    }

}
